/***************************************************************
*  Copyright (c) 2007 by GroupMe! Team (www.groupme.net)
*  All rights reserved.
*
*  This file is part of the GroupMe! Project. Source code of 
*  this project is closed and redistribution of this code is
*  prohibited. 
*  
*  Contact: http://www.groupme.net
*
*  This copyright notice MUST APPEAR in all copies of the file!
***************************************************************/
package net.groupme.search;

import java.util.Calendar;
import java.util.Collection;
import java.util.List;

import net.groupme.model.Group;
import net.groupme.model.Resource;
import net.groupme.model.Tag;
import net.groupme.model.User;
import net.groupme.search.strategy.SearchStrategy;
import net.groupme.search.strategy.TagSearchStrategy;
import net.groupme.search.strategy.UserSpecificSearchStrategy;
import net.groupme.search.strategy.model.WeightedTag;

/**
 * created on Jun 28, 2007
 * 
 * This is the core class of the internal GroupMe! search engine. Third parties can utilize
 * it via the <a href="http://groupme.org/api/">GroupMe! API</a>.
 * 
 * 
 * @author Fabian Abel, <a href="mailto:abel@l3s.de">abel@l3s.de</a>
 * @author last edited by: $Author: fabian $
 * 
 * @version $Revision: 1.9 $ $Date: 2008-05-07 18:17:57 $
 */
public class GroupMeSearchEngine {
	
	/** the underlying search strategy of this engine */
	private SearchStrategy searchStrategy = null; 
	
	/** the underlying {@link Tag} search strategy of this engine */
	private TagSearchStrategy tagSearchStrategy = null;
	
	/** the user-specific search strategy of this engine */
	private UserSpecificSearchStrategy userSpecificSearchStrategy = null;
	
	/**
	 * Creates a new GroupMeSearchEngine instance.
	 */
	public GroupMeSearchEngine(){
		super();
	}
	
	/**
	 * Creates a new GroupMeSearchEngine instance.
	 * @param strategy the strategy which will be used by this search engine.
	 * @param tagSearchStrategy strategy for searching for tags
	 */
	public GroupMeSearchEngine(SearchStrategy strategy, TagSearchStrategy tagSearchStrategy, UserSpecificSearchStrategy userSpecificSearchStrategy){
		super();
		this.searchStrategy = strategy;
		this.tagSearchStrategy = tagSearchStrategy;
		this.userSpecificSearchStrategy = userSpecificSearchStrategy;
	}

	/**
	 * This method returns the searchStrategy of a GroupMeSearchEngine object.
	 * @return the searchStrategy
	 */
	public SearchStrategy getSearchStrategy() {
		return searchStrategy;
	}

	/**
	 * This method sets the searchStrategy of a GroupMeSearchEngine object.
	 * @param searchStrategy the searchStrategy to set
	 */
	public void setSearchStrategy(SearchStrategy searchStrategy) {
		this.searchStrategy = searchStrategy;
	}
	
	
	/**
	 * This method returns the userSpecificSearchStrategy of a GroupMeSearchEngine object.
	 * @return the userSpecificSearchStrategy
	 */
	public UserSpecificSearchStrategy getUserSpecificSearchStrategy() {
		return userSpecificSearchStrategy;
	}

	/**
	 * This method sets the userSpecificSearchStrategy of a GroupMeSearchEngine object.
	 * @param userSpecificSearchStrategy the userSpecificSearchStrategy to set
	 */
	public void setUserSpecificSearchStrategy(
			UserSpecificSearchStrategy userSpecificSearchStrategy) {
		this.userSpecificSearchStrategy = userSpecificSearchStrategy;
	}

	/**
	 * This method sets the tagSearchStrategy of a GroupMeSearchEngine object.
	 * @param tagSearchStrategy the tagSearchStrategy to set
	 */
	public void setTagSearchStrategy(TagSearchStrategy tagSearchStrategy) {
		this.tagSearchStrategy = tagSearchStrategy;
	}

	/**
	 * This method simply redirects the search request to the underlying
	 * {@link SearchStrategy} instance that is actually used by this engine.
	 * Thus, it simply calls the method: {@link SearchStrategy#searchForGroups(Collection, boolean)}
	 * 
	 * @param tags the tags to search with
	 * @param allTags indicates whether all tags have to be related with a resulting group (<code>true</code>)
	 * or only any of the given tags (<code>false</code>)
	 * @return an ordered list of suiting {@link Group} instances
	 */
	public List<Group> searchForGroups(Collection<Tag> tags, boolean allTags){
		return searchStrategy.searchForGroups(tags, allTags);
	}
	
	/**
	 * This method simply redirects the search request to the underlying
	 * {@link SearchStrategy} instance that is actually used by this engine.
	 * Thus, it simply calls the method: {@link SearchStrategy#searchForResources(Collection, boolean)}
	 * 
	 * @param tag the tags to search with
	 * @param allTags indicates wheater all tags have to be related with a resulting group (<code>true</code>)
	 * or only any of the given tags (<code>false</code>)
	 * @param noGroups as {@link Group} instances are also {@link Resource} one can explicitly exclude {@link Group} instances by
	 * if this parameter is <code>false</code>
	 * @return an ordered list of suiting {@link Group} instances
	 */
	public List<Resource> searchForResources(Collection<Tag> tags,  boolean allTags, boolean noGroups){
		return searchStrategy.searchForResources(tags, allTags, noGroups);
	}

	
	/**
	 * This method returns an ordered list of {@link WeightedTag} instances. Ordering is done according
	 * to the number of occurences in the given period. Such a list builds the base for <i>Tag Clouds</i>.
	 * 
	 * @param beginOfPeriod start of period. If this is <code>null</code> then all tag occurences that have 
	 * a date lesser than <i>endOfPeriod</i> are considered. 
	 * @param endOfPeriod end of period. If this is <code>null</code> then all tag occurences that have 
	 * a date greater than <i>beginOfPeriod</i> are considered. 
	 * @param user the user who tagged the resources. If this is <code>null</code> then tag occurences of all 
	 * users are considerd.
	 * @param topK to specify the maximum number of tags that are contained in the tag cloud. If <code>topK</code> = 50 then the 50 most
	 * important tags are returned (50 most popular tags). If <code>topK == null</code> then all tags will be returned (this may take very long). 
	 * @return an ordered list of {@link WeightedTag} instances according to the number of occurences in the specified period of time
	 */
	public List<WeightedTag> getTagCloud(Calendar beginOfPeriod, Calendar endOfPeriod, User user, Integer topK){
		return tagSearchStrategy.getTagCloud(beginOfPeriod, endOfPeriod, user, topK);
	}
	
	/**
	 * This method returns the tag cloud of a group which is an ordered list of {@link WeightedTag} instances. 
	 * Ordering is done according to the number of occurences in the given period within the group. 
	 *  
	 * @param group the group about which the tag cloud should be 
	 * @param topK to specify the maximum number of tags that are contained in the tag cloud. If <code>topK</code> = 50 then the 50 most
	 * important tags are returned (50 most popular tags). If <code>topK == null</code> then all tags will be returned (this may take very long).
	 * @return an ordered list of {@link WeightedTag} instances according to the number of occurences in the specified period of time
	 */
	public List<WeightedTag> getTagCloud(Group group, Integer topK){
		return tagSearchStrategy.getTagCloud(group, topK);
	}
}
